﻿using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using YAKEJI.Xaf.Numbers;
using YAPACS.BusinessObjects.Exams;
using YAPACS.BusinessObjects.Managements.Exams;
using YAPACS.RisServer.Abstractions;

namespace YAPACS.RisServer.Services;

public class ExamNumberService(IRepository<ExamNumber, Guid> examNumberRepository, INumberService numberService) : DomainService, IExamNumberService, ITransientDependency
{
    private readonly IRepository<ExamNumber, Guid> _examNumberRepository = examNumberRepository;
    private readonly INumberService _numberService = numberService;

    public async Task<string> SetAppointmentNumberAsync(Exam exam)
    {
        string result = null;
        var departmentExamNumbers = await _examNumberRepository.GetListAsync(n => n.Department == exam.Department && n.IsActive);
        var appointmentNumber = departmentExamNumbers.FirstOrDefault(n => n.NumberType == ExamNumberType.AppointmentNumber);
        if (exam.ExamAppointment != null && string.IsNullOrWhiteSpace(exam.ExamAppointment.AppointmentNumber) && appointmentNumber != null)
        {
            var numberOptions = GetNumberOptions(appointmentNumber); // 获取生成规则
            exam.ExamAppointment.AppointmentNumber = await _numberService.GetNumberAsync(numberOptions, exam.ExamAppointment);
            result = exam.ExamAppointment.AppointmentNumber;
        }
        return result;
    }

    public async Task SetNumberAsync(Exam exam, bool disassemble = false)
    {
        var departmentExamNumbers = await _examNumberRepository.GetListAsync(n => n.Department == exam.Department && n.IsActive);
        var institutionExamNumbers = await _examNumberRepository.GetListAsync(n => n.Institution == exam.Department.Institution && n.IsActive);

        var patientIdNumber = departmentExamNumbers.FirstOrDefault(n => n.NumberType == ExamNumberType.PatientId);
        patientIdNumber ??= institutionExamNumbers.FirstOrDefault(n => n.NumberType == ExamNumberType.PatientId);
        var appointmentNumber = departmentExamNumbers.FirstOrDefault(n => n.NumberType == ExamNumberType.AppointmentNumber);
        var operationNumber = departmentExamNumbers.FirstOrDefault(n => n.NumberType == ExamNumberType.OperationNumber);
        if (exam.Patient != null && string.IsNullOrWhiteSpace(exam.Patient.PatientId) && patientIdNumber != null)
        {
            var numberOptions = GetNumberOptions(patientIdNumber);
            exam.Patient.PatientId = await _numberService.GetNumberAsync(numberOptions, exam);
        }

        if (string.IsNullOrWhiteSpace(exam.OperationNumber) && operationNumber != null)
        {
            var numberOptions = GetNumberOptions(operationNumber);
            exam.OperationNumber = await _numberService.GetNumberAsync(numberOptions, exam);
        }

        if (string.IsNullOrWhiteSpace(exam.AccessionNumber) && (exam.ExamQueuing != null || disassemble))
        {
            var accessionNumber = departmentExamNumbers
                .Where(n => n.NumberType == ExamNumberType.AccessionNumber)
                .Where(n => n.DeviceType == exam.DeviceType)
                .FirstOrDefault();
            if (accessionNumber != null)
            {
                var numberOptions = GetNumberOptions(accessionNumber);
                exam.AccessionNumber = await _numberService.GetNumberAsync(numberOptions, exam);
            }
        }
    }

    public async Task SetQueueNumberAsync(ExamQueuing queuing)
    {
        var departmentExamNumbers = await _examNumberRepository.GetListAsync(n => n.Department == queuing.Exam.Department && n.IsActive);
        var callNumber = departmentExamNumbers.FirstOrDefault(n => n.NumberType == ExamNumberType.CallNumber);
        var emergencyCallNumber = departmentExamNumbers.FirstOrDefault(n => n.NumberType == ExamNumberType.EmergencyCallNumber);
        var appointmentCallNumber = departmentExamNumbers.FirstOrDefault(n => n.NumberType == ExamNumberType.AppointmentCallNumber);

        var numberOptions = GetNumberOptions(callNumber);
        if (queuing.Exam.IsEmergency && emergencyCallNumber != null)
        {
            numberOptions = GetNumberOptions(emergencyCallNumber);
        }
        else if (queuing.Exam.IsAppointment && appointmentCallNumber != null)
        {
            numberOptions = GetNumberOptions(appointmentCallNumber);
        }

        queuing.CallNumber = await _numberService.GetNumberAsync(numberOptions, queuing);
    }

    private NumberOptions GetNumberOptions(ExamNumber examNumber)
    {
        return new NumberOptions
        {
            NumberId = examNumber.Oid.ToString(),
            NumberTemplate = examNumber.Template,
            KeyTemplate = examNumber.KeyTemplate,
            StartValue = examNumber.StartValue,
            Step = examNumber.Step,
            AllowRetrieve = examNumber.AllowRetrieve
        };
    }
}
